// 4位定点数
// 与 int/long混合计算 结果均为 定点数
// 正三角与反三角 以及开放运算 需要定制
// ！！！！FixedPoint 与 float/double等浮点数之间的转换，以及混合运算会存在平台差异性
#if UNITY_EDITOR
[System.Serializable]// 用于Unity Inspector
#endif
public struct FixedPoint : System.IEquatable<FixedPoint>, System.IComparable<FixedPoint>
{
    public const long denominator = 10000;
	public const long denominator_half = denominator / 2;
	public const long denominator_sqrt = 100;


	#if UNITY_EDITOR
	[UnityEngine.SerializeField]// 用于Unity Inspector
	#endif
    private long _value;

    public override int GetHashCode ()
	{
		return _value.GetHashCode ();
	}

    /// <summary>
    /// 内部原始值
    /// </summary>
    public long rawValue { get { return _value; } }
    /// <summary>
    /// 显示转换为float，不再提供定点数与非定点数的隐式转换，避免定点数与非定点数混合计算
    /// </summary>
    public float floatValue { get { return _value / (float)denominator; } }
    /// <summary>
    /// 显示转换为int
    /// </summary>
    public int intValue { get { return this.roundToInt; } }
    /// <summary>
    /// 用于生成代码时使用
    /// </summary>
	public string codeStr { get { return string.Format("new FixedPoint({0})", _value); } }

	// 9 位对齐字符串
	public string alignmentStr 
	{ 
		get 
		{
			long v = this._value;
			long abs = FixedMath.Abs(v);
			return string.Format("{0}{1}.{2}",
				v < 0? "-" : "",
				(abs / denominator),
				(abs % denominator).ToString().PadLeft(4, '0')
			).PadLeft(9);
		}
	}


	/// <summary>
	/// 开平方
	/// </summary>
	public FixedPoint Sqrt
	{
		get
		{
			return new FixedPoint((long)(FixedMath.Sqrt((ulong)this._value) * denominator_sqrt));
		}
	}


    public long floor
    {
    	get
    	{
			return _value % denominator;
    	}
    }

    public int floorToInt
 	{
 		get
 		{
			return (int)(_value / denominator);
 		}
 	}

 	public long round
 	{
 		get
 		{
			return (_value + denominator_half) / denominator;
 		}
 	}

 	public int roundToInt
 	{
 		get
 		{
			return (int)((_value + denominator_half) / denominator);
 		}
 	}

	public FixedPoint Round_Factor (long intervalFactor)
 	{
		return new FixedPoint((_value + intervalFactor / 2) / intervalFactor);
 	}

	public FixedPoint Round (FixedPoint interval)
 	{
		return this.Round_Factor(interval.rawValue);
 	}

	// 限定在某个范围内重复
	public FixedPoint Repeat (FixedPoint start, FixedPoint repeatLength)
 	{
		return start + (this - start) % repeatLength;
 	}

	// 限定在 0 ~ repeatLength 范围内重复
	// 测试ok
	public FixedPoint Repeat (FixedPoint repeatLength)
 	{
		return this % repeatLength;
 	}

 	// 原始值限定在某个范围内重复
 	public FixedPoint RawRepeat (long start, long repeatLength)
 	{
		return new FixedPoint(start + (_value - start) % repeatLength);
 	}

	// 原始值限定在 0 ~ repeatLength 范围内重复
	public FixedPoint RawRepeat (long repeatLength)
 	{
		return new FixedPoint(_value % repeatLength);
 	}

	/// 按固定间隔获取索引
	public int IndexOfInterval (FixedPoint interval)
 	{
		return (int)((_value + interval._value / 2) / interval._value);
 	}
	/// 按固定间隔获取索引
	public int IndexOfInterval (FixedPoint start, FixedPoint interval)
 	{
		return (int)((_value + interval._value / 2 + start._value) / interval._value);
 	}
	/// 按固定间隔获取索引
	public int IndexOfInterval_Factor (long interval)
 	{
		return (int)((_value + interval / 2) / interval);
 	}
	/// 按固定间隔获取索引
	public int IndexOfInterval_Factor (long start, long interval)
 	{
		return (int)((_value + interval / 2 - start) / interval);
 	}

    // 构造函数 
    // 传入原始值
	public FixedPoint (long rawValue)
	{
		_value = rawValue;
    }

	public override bool Equals(object obj) 
	{
		return obj is FixedPoint && ((FixedPoint)obj)._value == _value;
	}

	public bool Equals (FixedPoint other)
	{
		return _value == other._value;
	}

	public int CompareTo(FixedPoint other) 
	{
		return _value.CompareTo(other._value);
	}

	public override string ToString ()
	{
		return this.floatValue.ToString();
	}

	public FixedPoint Abs ()
	{
		return this._value < 0? new FixedPoint(-this._value) : this;
//		FixedPoint ret = this;
//		ret._value = _value < 0? -_value : _value;
//		return ret;
	}

	public FixedPoint Clamp (FixedPoint min, FixedPoint max)
	{
		long rawValue = this._value;

		if (rawValue < min._value) rawValue = min._value;
		else if (rawValue > max._value) rawValue = max._value;

		return new FixedPoint(rawValue);
	}
	public FixedPoint Clamp01 ()
	{
		long rawValue = this._value;

		if (rawValue < 0) rawValue = 0;
		else if (rawValue > denominator) rawValue = denominator;

		return new FixedPoint(rawValue);
	}


	/// 0
	public static readonly FixedPoint Zero = new FixedPoint(0);
	/// 最小粒度
	public static readonly FixedPoint Epsilon = new FixedPoint(1);
	/// 1
	public static readonly FixedPoint One = new FixedPoint(denominator);
	public static readonly FixedPoint Half = new FixedPoint(denominator_half);
	/// 2
	public static readonly FixedPoint Two = new FixedPoint(denominator * 2);
	/// 3
	public static readonly FixedPoint Three = new FixedPoint(denominator * 3);
	/// -1
	public static readonly FixedPoint NegativeOne = new FixedPoint(-denominator);

    /// <summary>
    ///   表示正无穷。
    ///    此字段为常数。
    /// </summary>
    public static readonly FixedPoint PositiveInfinity = new FixedPoint(long.MaxValue);
    /// <summary>
    ///   表示负无穷。
    ///    此字段为常数。
    /// </summary>
    public static readonly FixedPoint NegativeInfinity = new FixedPoint(long.MinValue + 1);
    /// <summary>
    ///   表示非数字 (<see langword="NaN" />)。
    ///    此字段为常数。
    /// </summary>
    public static readonly FixedPoint NaN = new FixedPoint(long.MinValue);

    /* // 去掉与float的隐式转换，避免在使用定点数时，不小心与1f等混合计算, 换成非常明显的API FromFloat
	// float -> FixedPoint
    public static implicit operator FixedPoint (float v)
	{
		return new FixedPoint((long)(v * denominator));
	}*/

    /// <summary>
    /// 从float进行构造，由于存在浮点计算，会存在平台差异
    /// </summary>
    public static FixedPoint FromFloat(float v)
	{
		return new FixedPoint((long)(v * denominator));
	}
	/// <summary>
	/// 从double进行构造，由于存在浮点计算，会存在平台差异
	/// </summary>
	public static FixedPoint FromDouble(double v)
	{
		return new FixedPoint((long)(v * denominator));
	}

	/*
	// double -> FixedPoint
    public static implicit operator FixedPoint (double v)
	{
		return new FixedPoint((long)(v * denominator));
	}
	*/
	// int -> FixedPoint
	public static implicit operator FixedPoint (int v)
	{
		return new FixedPoint(v * denominator);
	}
	// long -> FixedPoint
	public static implicit operator FixedPoint (long v)
	{
		return new FixedPoint(v * denominator);
	}

	/* // 去掉与float的隐式转换，避免在使用定点数时，不小心与1f等混合计算， 换成非常明显的API .floatValue
	// FixedPoint -> float
	// Fixed隐式转换其他基本类型 只留float 防呆
	public static implicit operator float (FixedPoint v)
	{
		return v.floatValue;
	}
	*/


	public static FixedPoint operator + (FixedPoint a)
	{
		return a;
	}
	public static FixedPoint operator - (FixedPoint a) 
	{
		return new FixedPoint(-a._value);
	}
	/// 重载操作符 ==
	public static bool operator == (FixedPoint a, FixedPoint b) 
	{
		return a._value == b._value;
	}
	/// 重载操作符 !=
	public static bool operator != (FixedPoint a, FixedPoint b) 
	{
		return a._value != b._value;
	}
	/// 重载操作符 >
	public static bool operator > (FixedPoint a, FixedPoint b) 
	{
		return a._value > b._value;
	}
	/// 重载操作符 >=
	public static bool operator >= (FixedPoint a, FixedPoint b) 
	{
		return a._value >= b._value;
	}
	/// 重载操作符 <
	public static bool operator < (FixedPoint a, FixedPoint b) 
	{
		return a._value < b._value;
	}
	/// 重载操作符 <=
	public static bool operator <= (FixedPoint a, FixedPoint b) 
	{
		return a._value <= b._value;
	}

	// 与long对比 
	public static bool operator > (FixedPoint a, long b) 
	{
		return a._value > b * denominator;
	}
	public static bool operator < (FixedPoint a, long b) 
	{
		return a._value < b * denominator;
	}
	public static bool operator > (long a, FixedPoint b) 
	{
		return a * denominator > b._value;
	}
	public static bool operator < (long a, FixedPoint b) 
	{
		return a * denominator < b._value;
	}

	#region Fixed4Point +-*/ Fixed4Point 
	/// 重载操作 + 
    public static FixedPoint operator + (FixedPoint a, FixedPoint b) 
	{
		return new FixedPoint(a._value + b._value);
	}
    public static FixedPoint operator - (FixedPoint a, FixedPoint b) 
	{
		return new FixedPoint(a._value - b._value);
	}
    public static FixedPoint operator * (FixedPoint a, FixedPoint b) 
	{
		return new FixedPoint((a._value * b._value) / denominator);
	}
    public static FixedPoint operator / (FixedPoint a, FixedPoint b) 
	{
		return new FixedPoint((a._value * denominator / b._value));
	}
	#endregion

	// Fixed4Point +-*/ long/int
	public static FixedPoint operator + (FixedPoint a, long b) 
	{
		return new FixedPoint(a._value + b * denominator);
	}
    public static FixedPoint operator - (FixedPoint a, long b) 
	{
		return new FixedPoint(a._value - b * denominator);
	}
    public static FixedPoint operator * (FixedPoint a, long b) 
	{
		return new FixedPoint(a._value * b);
	}
    public static FixedPoint operator / (FixedPoint a, long b) 
	{
		return new FixedPoint(a._value / b);
	}

	// long/int +-*/ Fixed4Point
	public static FixedPoint operator + (long a, FixedPoint b) 
	{
		return new FixedPoint(a * denominator + b._value);
	}
    public static FixedPoint operator - (long a, FixedPoint b) 
	{
		return new FixedPoint(a * denominator - b._value);
	}
    public static FixedPoint operator * (long a, FixedPoint b) 
	{
		return new FixedPoint(a * b._value);
	}
    public static FixedPoint operator / (long a, FixedPoint b) 
	{
		return new FixedPoint(a * denominator * denominator / b._value);
	}

	/// 模除 
	public static FixedPoint operator % (FixedPoint a, FixedPoint b)
	{
		return new FixedPoint(a._value % b._value);
	}
	public static FixedPoint operator % (FixedPoint a, long b)
	{
		return new FixedPoint(a._value % b * denominator);
	}

	// 使用FixedMath
	/*
	public static FixedPoint Atan(FixedPoint y) 
	{
        return Atan2(y, 1);
    }*/

	public static readonly FixedPoint EN1 = new FixedPoint(1000);
	public static readonly FixedPoint EN2 = new FixedPoint(100);
	public static readonly FixedPoint EN3 = new FixedPoint(10);
	public static readonly FixedPoint EN4 = new FixedPoint(1);

	public static FixedPoint PI_Half = new FixedPoint(15708);
	public static readonly FixedPoint PI = new FixedPoint(31416);

	// 使用FixedMath
	/*
	public static FixedPoint Atan2(FixedPoint y, FixedPoint x) 
    {
        long yRawValue = y._value;
        long xRawValue = x._value;

        if (xRawValue == 0) 
        {
            if (yRawValue > 0) 
            {
				return PI_Half;
            }
            if (yRawValue == 0) 
            {
                return Zero;
            }
			return -PI_Half;
        }

		FixedPoint atan;

		FixedPoint z = y / x;

		FixedPoint sm = FixedPoint.EN2 * 28;
        // 极限溢出
        if (One + sm * z * z >= new FixedPoint((long)(int.MaxValue) * 10000)) 
        {
			return y < Zero ? -PI_Half : PI_Half;
        }

        if (z.Abs() < One) 
        {
            atan = z / (One + sm * z * z);
            if (xRawValue < 0) 
            {
                if (yRawValue < 0) 
                {
					return atan - PI;
                }
				return atan + PI;
            }
        } 
        else 
        {
			atan = PI_Half - z / (z * z + sm);
            if (yRawValue < 0) 
            {
				return atan - PI;
            }
        }
        return atan;
    }*/
}

#if UNITY_EDITOR
[System.Serializable]
#endif
public struct FixedVec2 : System.IEquatable<FixedVec2>
{
    public FixedPoint x;
    public FixedPoint y;

	public FixedVec2 (FixedPoint x, FixedPoint y)
	{
		this.x = x;
		this.y = y;
	}

	public override bool Equals(object obj) 
	{
		return obj is FixedVec2 && this.Equals((FixedVec2) obj);
	}

	public bool Equals (FixedVec2 other)
	{
		return this.x == other.x && this.y == other.y;
	}

	public override int GetHashCode ()
	{
		return this.x.GetHashCode () ^ this.y.GetHashCode () << 2;
	}


	#if UNITY_EDITOR || UNITY_IOS || UNITY_ANDROID || UNITY_STANDALONE
	/*
	/// 在Unity下与Vector2互转
	public static implicit operator FixedVec2 (UnityEngine.Vector2 v)
	{
		return new FixedVec2(v.x, v.y);
	}
	/// 在Unity下与Vector2互转
	public static implicit operator UnityEngine.Vector2 (FixedVec2 v)
	{
		return new UnityEngine.Vector2(v.x.floatValue, v.y.floatValue);
	}
	/// 在Unity下与Vector3互转
	public static implicit operator FixedVec2 (UnityEngine.Vector3 v)
	{
		return new FixedVec2(v.x, v.y);
	}
	/// 在Unity下与Vector3互转
	public static implicit operator UnityEngine.Vector3 (FixedVec2 v)
	{
		return new UnityEngine.Vector3(v.x.floatValue, v.y.floatValue, 0);
	}
	*/

	public static FixedVec2 FromUnityVector2(UnityEngine.Vector2 v)
	{
		return new FixedVec2(FixedPoint.FromFloat(v.x), FixedPoint.FromFloat(v.y));
	}
	public UnityEngine.Vector2 UnityVector2 => new UnityEngine.Vector2(this.x.floatValue, this.y.floatValue);
	#endif

	public override string ToString ()
	{
		return string.Format ("({0:F1}, {1:F1})", this.x,this.y);
	}

	public static readonly FixedVec2 zero = new FixedVec2(FixedPoint.Zero, FixedPoint.Zero);
	public static readonly FixedVec2 Zero = new FixedVec2(FixedPoint.Zero, FixedPoint.Zero);
	public static readonly FixedVec2 Epsilon = new FixedVec2(FixedPoint.Epsilon, FixedPoint.Epsilon);

	// 开放的定点运算需要重写
	public FixedPoint magnitude { get{ return FixedMath.Sqrt (this.x * this.x + this.y * this.y);}}
	public FixedPoint sqrMagnitude { get{ return this.x * this.x + this.y * this.y;}}

	public void Normalize ()
	{
		FixedPoint magnitude = this.magnitude;
		if (magnitude == FixedPoint.Zero) 
		{
			this = FixedVec2.zero;
		}
		else 
		{
			this /= magnitude;
		}
	}

	public FixedVec2 normalized 
	{
		get 
		{
			FixedVec2 result = new FixedVec2 (this.x, this.y);
			result.Normalize ();
			return result;
		}
	}

	public FixedPoint FourQuadrantAngle
	{
		get
		{
			if (this.y == 0)
			{
				if (this.x >= 0)
				{
					return 0;
				}
				else
				{
					return 180;
				}
			}

			if (this.x == 0)
			{
				if (this.y > 0)
				{
					return 90;
				}
				else
				{
					return 270;
				}
			}

			//FixedPoint angle = (float)(System.Math.Atan (this.y / this.x) * 180 / System.Math.PI);
			FixedPoint angle = FixedMath.Radian2Angle(FixedMath.Atan (this.y / this.x));
	
			if (this.x < 0)
			{
				// 二三象限 需要+180
				angle += 180;
			}
			else if (this.y < 0)
			{
				// 四象限 为-180~0,转化为270~360
				angle += 360;
			}

			return angle;
		}
	}

	public static FixedPoint Dot (FixedVec2 a, FixedVec2 b)
	{
		return a.x * b.x + a.y * b.y;
	}

	/// 向量a 在 向量 b上的投影长度 
	public static FixedPoint Project (FixedVec2 a, FixedVec2 b)
	{
		return Dot(a, b.normalized);
	}

	private static FixedPoint Clamp (FixedPoint value, FixedPoint min, FixedPoint max)
	{
		if (value < min) 
		{
			value = min;
		}
		else 
		{
			if (value > max) 
			{
				value = max;
			}
		}
		return value;
	}

	public static FixedPoint Angle (FixedVec2 from, FixedVec2 to)
	{
		//return (FixedMath.Acos(Clamp(FixedVec2.Dot(from.normalized, to.normalized), -1, 1)) * 57.29578);
		return FixedMath.Acos(Clamp(FixedVec2.Dot(from.normalized, to.normalized), -1, 1)) * new FixedPoint(572958);
	}


    public static FixedVec2 Reflect (FixedVec2 inDirection, FixedVec2 inNormal)
	{
		return -2 * FixedVec2.Dot (inNormal, inDirection) * inNormal + inDirection;
	}

	//
	// Operators
	//
	public static FixedVec2 operator + (FixedVec2 a, FixedVec2 b) 
	{
		return new FixedVec2 (a.x + b.x, a.y + b.y);
	}
	public static FixedVec2 operator / (FixedVec2 a, FixedPoint b) 
	{
		return new FixedVec2 (a.x / b, a.y / b);
	}
	public static bool operator == (FixedVec2 a, FixedVec2 b) 
	{
		return a.x == b.x && a.y == b.y;
	}
	public static bool operator != (FixedVec2 a, FixedVec2 b) 
	{
		return a.x != b.x || a.y != b.y;
	}
	public static FixedVec2 operator * (FixedPoint a, FixedVec2 b) 
	{
		return new FixedVec2 (b.x * a, b.y * a);
	}
	public static FixedVec2 operator * (FixedVec2 a, FixedPoint b) 
	{
		return new FixedVec2 (a.x * b, a.y * b);
	}
	public static FixedVec2 operator - (FixedVec2 a, FixedVec2 b) 
	{
		return new FixedVec2 (a.x - b.x, a.y - b.y);
	}
	public static FixedVec2 operator - (FixedVec2 a) 
	{
		return new FixedVec2 (-a.x, -a.y);
	}


	/// 点到直线的平方距离(矢量算法)
	public FixedPoint sqrDistanceToLine(FixedVec2 point1, FixedVec2 point2)
	{
		FixedPoint dot = (point2.x - point1.x) * (this.x - point1.x) + (point2.y - point1.y) * (this.y - point1.y);
		FixedPoint sqrmag = (point2.x - point1.x) * (point2.x - point1.x) + (point2.y - point1.y) * (point2.y - point1.y);
		FixedPoint rate = dot / sqrmag;
		FixedPoint px = point1.x + (point2.x - point1.x) * rate;
		FixedPoint py = point1.y + (point2.y - point1.y) * rate;
		return (this.x - px) * (this.x - px) + (py - this.y) * (py - this.y);
	}
	/// 点到直线的距离(矢量算法)
	public FixedPoint distanceToLine(FixedVec2 point1, FixedVec2 point2)
	{
		return FixedMath.Sqrt(this.sqrDistanceToLine(point1, point2));
	}
	/// 点到线段的平方距离(!非直线)(矢量算法)
	public FixedPoint sqrDistanceToSegment(FixedVec2 point1, FixedVec2 point2)
	{
		FixedPoint dot = (point2.x - point1.x) * (this.x - point1.x) + (point2.y - point1.y) * (this.y - point1.y);
		if (dot <= 0) return (this.x - point1.x) * (this.x - point1.x) + (this.y - point1.y) * (this.y - point1.y);

		FixedPoint sqrmag = (point2.x - point1.x) * (point2.x - point1.x) + (point2.y - point1.y) * (point2.y - point1.y);
		if (dot >= sqrmag) return (this.x - point2.x) * (this.x - point2.x) + (this.y - point2.y) * (this.y - point2.y);

		FixedPoint rate = dot / sqrmag;
		FixedPoint px = point1.x + (point2.x - point1.x) * rate;
		FixedPoint py = point1.y + (point2.y - point1.y) * rate;
		return (this.x - px) * (this.x - px) + (py - this.y) * (py - this.y);
	}
	/// 点到线段的距离(!非直线)(矢量算法)
	public FixedPoint distanceOfPointToSegment(FixedVec2 point, FixedVec2 point2)
	{
		return FixedMath.Sqrt(this.sqrDistanceToSegment(point, point2));
	}
}


//TODO 检查 可能会有问题
#if UNITY_EDITOR
[System.Serializable]
#endif
public struct FixedVec3 : System.IEquatable<FixedVec3>
{
    public FixedPoint x;
    public FixedPoint y;
    public FixedPoint z;

    public FixedVec3(FixedPoint x, FixedPoint y, FixedPoint z)
    {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public override bool Equals(object obj)
    {
        return obj is FixedVec3 && this.Equals((FixedVec3)obj);
    }

    public bool Equals(FixedVec3 other)
    {
        return this.x == other.x && this.y == other.y && this.z == other.z;
    }

    public override int GetHashCode()
    {
        return this.x.GetHashCode() ^ this.y.GetHashCode() ^ this.z.GetHashCode() << 3;
    }


#if UNITY_EDITOR || UNITY_IOS || UNITY_ANDROID || UNITY_STANDALONE
	/*
    /// 在Unity下与Vector2互转
    public static implicit operator FixedVec3(UnityEngine.Vector2 v)
    {
        return new FixedVec3(v.x, v.y, 0);
    }
    /// 在Unity下与Vector2互转
    public static implicit operator UnityEngine.Vector2(FixedVec3 v)
    {
        return new UnityEngine.Vector2(v.x.floatValue, v.y.floatValue);
    }
    /// 在Unity下与Vector3互转
    public static implicit operator FixedVec3(UnityEngine.Vector3 v)
    {
        return new FixedVec3(v.x, v.y, v.z);
    }
    /// 在Unity下与Vector3互转
    public static implicit operator UnityEngine.Vector3(FixedVec3 v)
    {
        return new UnityEngine.Vector3(v.x.floatValue, v.y.floatValue, v.z.floatValue);
    }
    */
	
	/// <summary>
	/// 此转换会存在平台差异性
	/// </summary>
	public static FixedVec3 FromUnityVector3(UnityEngine.Vector3 v)
	{
		return new FixedVec3(FixedPoint.FromFloat(v.x),  FixedPoint.FromFloat(v.y), FixedPoint.FromFloat(v.z));
	}
	public UnityEngine.Vector3 UnityVector3 => new UnityEngine.Vector3(this.x.floatValue, this.y.floatValue, this.z.floatValue);
#endif

    public override string ToString()
    {
        return string.Format("({0:F1}, {1:F1}, {2:F1})", this.x, this.y, this.z);
    }

    public static readonly FixedVec3 zero = new FixedVec3(FixedPoint.Zero, FixedPoint.Zero, FixedPoint.Zero);
    public static readonly FixedVec3 Zero = new FixedVec3(FixedPoint.Zero, FixedPoint.Zero, FixedPoint.Zero);
    public static readonly FixedVec3 Epsilon = new FixedVec3(FixedPoint.Epsilon, FixedPoint.Epsilon, FixedPoint.Epsilon);

    public static readonly FixedVec3 One = new FixedVec3(FixedPoint.One, FixedPoint.One, FixedPoint.One);
    public static readonly FixedVec3 up = new FixedVec3(FixedPoint.Zero, FixedPoint.One, FixedPoint.Zero);

    // 开放的定点运算需要重写
    public FixedPoint magnitude { get { return FixedMath.Sqrt(this.x * this.x + this.y * this.y + this.z * this.z); } }
    public FixedPoint sqrMagnitude { get { return this.x * this.x + this.y * this.y + this.z * this.z; } }

    public void Normalize()
    {
        FixedPoint magnitude = this.magnitude;
        if (magnitude == FixedPoint.Zero)
        {
            this = FixedVec3.zero;
        }
        else
        {
            this /= magnitude;
        }
    }

    public FixedVec3 normalized
    {
        get
        {
            FixedVec3 result = new FixedVec3(this.x, this.y, this.z);
            result.Normalize();
            return result;
        }
    }

    //public FixedPoint FourQuadrantAngle
    //{
    //    get
    //    {
    //        if (this.y == 0)
    //        {
    //            if (this.x >= 0)
    //            {
    //                return 0;
    //            }
    //            else
    //            {
    //                return 180;
    //            }
    //        }

    //        if (this.x == 0)
    //        {
    //            if (this.y > 0)
    //            {
    //                return 90;
    //            }
    //            else
    //            {
    //                return 270;
    //            }
    //        }

    //        //FixedPoint angle = (float)(System.Math.Atan (this.y / this.x) * 180 / System.Math.PI);
    //        FixedPoint angle = FixedMath.Radian2Angle(FixedMath.Atan(this.y / this.x));

    //        if (this.x < 0)
    //        {
    //            // 二三象限 需要+180
    //            angle += 180;
    //        }
    //        else if (this.y < 0)
    //        {
    //            // 四象限 为-180~0,转化为270~360
    //            angle += 360;
    //        }

    //        return angle;
    //    }
    //}

    public static FixedPoint Dot(FixedVec3 a, FixedVec3 b)
    {
        return a.x * b.x + a.y * b.y + a.z * b.z;
    }

    /// 向量a 在 向量 b上的投影长度 
    public static FixedPoint Project(FixedVec3 a, FixedVec3 b)
    {
        return Dot(a, b.normalized);
    }

    private static FixedPoint Clamp(FixedPoint value, FixedPoint min, FixedPoint max)
    {
        if (value < min)
        {
            value = min;
        }
        else
        {
            if (value > max)
            {
                value = max;
            }
        }
        return value;
    }
    
    public static FixedVec3 Cross(FixedVec3 v1, FixedVec3 v2)
    {
	    return new FixedVec3(v1.y *  v2.z -  v1.z *  v2.y, v1.z *  v2.x -  v1.x *  v2.z, v1.x *  v2.y -  v1.y *  v2.x);
    }

    public static FixedPoint Angle(FixedVec3 from, FixedVec3 to)
    {
        //return (FixedMath.Acos(Clamp(FixedVec3.Dot(from.normalized, to.normalized), -1, 1)) * 57.29578);
        return FixedMath.Acos(Clamp(FixedVec3.Dot(from.normalized, to.normalized), -1, 1)) * new FixedPoint(572958);
    }



    public static FixedVec3 Reflect(FixedVec3 inDirection, FixedVec3 inNormal)
    {
        return -2 * FixedVec3.Dot(inNormal, inDirection) * inNormal + inDirection;
    }

	public static FixedVec3 Lerp (FixedVec3 a, FixedVec3 b, FixedPoint t)
	{
		return a + (b - a) * t;
	}

    //
    // Operators
    //
    public static FixedVec3 operator +(FixedVec3 a, FixedVec3 b)
    {
        return new FixedVec3(a.x + b.x, a.y + b.y, a.z + b.z);
    }
    public static FixedVec3 operator /(FixedVec3 a, FixedPoint b)
    {
        return new FixedVec3(a.x / b, a.y / b, a.z / b);
    }
    public static bool operator ==(FixedVec3 a, FixedVec3 b)
    {
        return a.x == b.x && a.y == b.y && a.z == b.z;
    }
    public static bool operator !=(FixedVec3 a, FixedVec3 b)
    {
        return a.x != b.x || a.y != b.y || a.z != b.z;
    }
    public static FixedVec3 operator *(FixedPoint a, FixedVec3 b)
    {
        return new FixedVec3(b.x * a, b.y * a, b.z * a);
    }
    public static FixedVec3 operator *(FixedVec3 a, FixedPoint b)
    {
        return new FixedVec3(a.x * b, a.y * b, a.z * b);
    }
    public static FixedVec3 operator -(FixedVec3 a, FixedVec3 b)
    {
        return new FixedVec3(a.x - b.x, a.y - b.y, a.z - b.z);
    }
    public static FixedVec3 operator -(FixedVec3 a)
    {
        return new FixedVec3(-a.x, -a.y, -a.z);
    }


    /// 点到直线的平方距离(矢量算法)
    public FixedPoint sqrDistanceToLine(FixedVec3 point1, FixedVec3 point2)
    {
        FixedPoint dot = (point2.x - point1.x) * (this.x - point1.x) + (point2.y - point1.y) * (this.y - point1.y) + (point2.z - point1.z) * (this.z - point1.z);
        FixedPoint sqrmag = (point2.x - point1.x) * (point2.x - point1.x) + (point2.y - point1.y) * (point2.y - point1.y) + (point2.z - point1.z) * (point2.z - point1.z);
        FixedPoint rate = dot / sqrmag;
        FixedPoint px = point1.x + (point2.x - point1.x) * rate;
        FixedPoint py = point1.y + (point2.y - point1.y) * rate;
        FixedPoint pz = point1.z + (point2.z - point1.z) * rate;
        return (this.x - px) * (this.x - px) + (py - this.y) * (py - this.y) + (pz - this.z) * (pz - this.z);
    }
    /// 点到直线的距离(矢量算法)
    public FixedPoint distanceToLine(FixedVec3 point1, FixedVec3 point2)
    {
        return FixedMath.Sqrt(this.sqrDistanceToLine(point1, point2));
    }
    /// 点到线段的平方距离(!非直线)(矢量算法)
    public FixedPoint sqrDistanceToSegment(FixedVec3 point1, FixedVec3 point2)
    {
        FixedPoint dot = (point2.x - point1.x) * (this.x - point1.x) + (point2.y - point1.y) * (this.y - point1.y) + (point2.z - point1.z) * (this.z - point1.z);
        if (dot <= 0) return (this.x - point1.x) * (this.x - point1.x) + (this.y - point1.y) * (this.y - point1.y) + (this.z - point1.z) * (this.z - point1.z);

        FixedPoint sqrmag = (point2.x - point1.x) * (point2.x - point1.x) + (point2.y - point1.y) * (point2.y - point1.y) + (point2.z - point1.z) * (point2.z - point1.z);
        if (dot >= sqrmag) return (this.x - point2.x) * (this.x - point2.x) + (this.y - point2.y) * (this.y - point2.y) + (this.z - point2.z) * (this.z - point2.z);

        FixedPoint rate = dot / sqrmag;
        FixedPoint px = point1.x + (point2.x - point1.x) * rate;
        FixedPoint py = point1.y + (point2.y - point1.y) * rate;
        FixedPoint pz = point1.z + (point2.z - point1.z) * rate;
        return (this.x - px) * (this.x - px) + (py - this.y) * (py - this.y) + (pz - this.z) * (pz - this.z);
    }
    /// 点到线段的距离(!非直线)(矢量算法)
    public FixedPoint distanceOfPointToSegment(FixedVec3 point, FixedVec3 point2)
    {
        return FixedMath.Sqrt(this.sqrDistanceToSegment(point, point2));
    }
}
